/**
* project3D Engine
* @author John Sword
* @version 2 - AS3
*/

package engine.geom
{
	
	public class Vector
	{
		public var x:Number;
		public var y:Number;
		public var z:Number;
		public var num:Number;

		/**
		* Create a new Vector
		* 
		* @param x the x coordinate
		* @param y the y coordinate
		* @param z the z coordinate
		*/ 	
		public function Vector ( x:Number = 0, y:Number = 0, z:Number = 0)
		{
			this.x = x || 0;
			this.y = y || 0;
			this.z = z || 0;
		}

		public function clone () : Vector
		{
			return new Vector ( x, y, z );
		}
		
		public function toString () : String
		{
			return "x: " + x + " y: " + y + " z:" + z;
		}
		
		/**
	     *
	     * <code>subtract</code>
	     *
	     * @param vec
	     *            the vector to subtract from this
	     * @param result
	     *            the vector to store the result in
	     * @return result
	     */
	    public function subtract ( vec:Vector, result:Vector = null ) : Vector
	    {
	        if (result == null) result = new Vector();
	        result.x = x - vec.x;
	        result.y = y - vec.y;
	        result.z = z - vec.z;
	        return result;
	    }
	    
	    /**
	     * <code>subtractLocal</code> subtracts a provided vector with this vector internally,
	     * and returns a handle to this vector for easy chaining of calls. 
	     *
	     * @param vec
	     *            the vector to subtract from this vector.
	     * @return this
	     */
	    public function subtractLocal ( vec:Vector ) : Vector
	    {
	    	x -= vec.x;
	        y -= vec.y;
	        z -= vec.z;
	        return this;
	    }
	    
	    /**
	     * <code>addLocal</code> adds a provided vector to this vector internally,
	     * and returns a handle to this vector for easy chaining of calls. If the
	     * provided vector is null, null is returned.
	     *
	     * @param vec
	     *            the vector to add to this vector.
	     * @return this
	     */
	    public function addLocal ( vec:Vector ) : Vector
	    {
	        x += vec.x;
	        y += vec.y;
	        z += vec.z;
	        return this;
	    }
	    
	     /**
	     * <code>cross</code> calculates the cross product of this vector with a
	     * parameter vector v.  The result is stored in <code>result</code>
	     *
	     * @param vec
	     *            the vector to cross with.
	     * @param result
	     *            the vector to store the cross product result.
	     * @return result, after recieving the cross product vector.
	     */
	    public function cross( vec:Vector, result:Vector = null ) : Vector
	    {
	        if (result == null) result = new Vector();
	        result.x = ((y * vec.z) - (z * vec.y)); 
	        result.y = ((z * vec.x) - (x * vec.z));
	        result.z = ((x * vec.y) - (y * vec.x));
	        return result;
	    }
	    
	    /**
		 * <code>crossLocal</code> calculates the cross product of this vector
		 * with a parameter vector v.
		 *
		 * @param vec
	     *            the vector to cross with this vector.
		 * @return this.
		 */
		public function crossLocal ( vec:Vector ) : Vector
		{
		    var tempx:Number = ( y * vec.z ) - ( z * vec.y );
		    var tempy:Number = ( z * vec.x ) - ( x * vec.z );
		    z = ( x * vec.y ) - ( y * vec.x );
		    x = tempx;
		    y = tempy;
		    return this;
		}
	    
	    /**
	     *
	     * <code>dot</code> calculates the dot product of this vector with a
	     * provided vector. If the provided vector is null, 0 is returned.
	     *
	     * @param vec
	     *            the vector to dot with this vector.
	     * @return the resultant dot product of this vector and a given vector.
	     */
	    public function dot ( vec:Vector ) : Number
	    {
	        return x * vec.x + y * vec.y + z * vec.z;
	    }
	    
	    /**
	     * <code>normalize</code> returns the unit vector of this vector.
	     *
	     * @return unit vector of this vector.
	     */
	    public function normalize() : Vector
	    {
	        var length:Number = length();
	        if (length != 0) {
	            return divide(length);
	        }
	        return divide(1);        
	    }
		
		/**
	     * <code>divide</code> divides the values of this vector by a scalar and
	     * returns the result. The values of this vector remain untouched.
	     *
	     * @param scalar
	     *            the value to divide this vectors attributes by.
	     * @return the result <code>Vector</code>.
	     */
	    public function divide ( scalar:Number ) : Vector 
	    {
	        scalar = 1/scalar;
	        return new Vector(x * scalar, y * scalar, z * scalar);
	    }
		
		/**
	     * <code>length</code> calculates the magnitude of this vector.
	     *
	     * @return the length or magnitude of the vector.
	     */
	    public function length() : Number
	    {
	        return Math.sqrt( lengthSquared() );
	    }
	
	    /**
	     * <code>lengthSquared</code> calculates the squared value of the
	     * magnitude of the vector.
	     *
	     * @return the magnitude squared of the vector.
	     */
	    public function lengthSquared() : Number
	    {
	        return x * x + y * y + z * z;
	    }
		
	    /**
	     * <code>set</code> sets the x,y,z values of the vector by copying the
	     * supplied vector.
	     *
	     * @param vect
	     *            the vector to copy.
	     * @return this vector
	     */
	    public function set ( vect:Vector ) : Vector
	    {
	        this.x = vect.x;
	        this.y = vect.y;
	        this.z = vect.z;
	        return this;
	    }
	
	    /*
	    public function getPoint3D () : Point3D
	    {
	    	return new Point3D( x,y,z );
	    }
		*/
	}

}